package com.ht.aems.fesmodel;

import com.ht.aems.fesmodel.data.AnalogPoint;
import com.ht.aems.fesmodel.data.DiscretePoint;
import com.ht.aems.fesmodel.data.MeasurePoint;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by IntelliJ IDEA.
 *
 * @author Dong Shufeng
 *         Date: 2010-8-6
 */
public class PointManager {//todo: not finished
    private static PointManager instance;
    private MeasPersistence persistence;
    private Map<Integer, AnalogPoint> analogPoints;
    private Map<String, AnalogPoint> name2AlgPoint;
    private Map<Integer, DiscretePoint> discreatePoints;
    private Map<String, DiscretePoint> name2DisPoint;

    public String getCommUnitNode() {
        return commUnitNode;
    }

    private String commUnitNode;
    private List<CommUnit> commUnits;

    private PointManager() {
        this.persistence = FesPersistenceFactory.createMeasPersistence();
        reload();
    }

    public PointManager(String nodeName) {
        this.commUnitNode = nodeName;
        reload();
    }

    public PointManager(int rtuId) {
        CommUnit commUnit = FesPersistenceFactory.createPersistence().getCommUnit(rtuId);
        this.commUnitNode = commUnit.getName();
        reload();
    }

    public void reload() {
        if(commUnitNode == null) {
            AnalogPoint[] points = persistence.getAllAnalogPoints();
            DiscretePoint[] points2 = persistence.getAllDiscretePoints();
            analogPoints = new HashMap<Integer, AnalogPoint>(points.length);
            name2AlgPoint = new HashMap<String, AnalogPoint>(points.length);
            fillMap(points, points2);
        } else {
            commUnits = FesPersistenceFactory.createPersistence().getCommUnitByName(commUnitNode);
            this.persistence = FesPersistenceFactory.createMeasPersistence();
            if (commUnits == null) {
                fillMap(new AnalogPoint[]{}, new DiscretePoint[]{});
            } else {
                analogPoints = new HashMap<Integer, AnalogPoint>();
                name2AlgPoint = new HashMap<String, AnalogPoint>();
                for (CommUnit u : commUnits) {
                    AnalogPoint[] analogPoints = persistence.getAnalogPoints(u.getId());
                    DiscretePoint[] discretePoints = persistence.getDiscretePoints(u.getId());
                    fillMap(analogPoints, discretePoints);
                }
            }
        }
    }

    private void fillMap(AnalogPoint[] points, DiscretePoint[] points2) {
        for (AnalogPoint p : points) {
            analogPoints.put(p.getId(), p);
            name2AlgPoint.put(p.getName(), p);
        }
        discreatePoints = new HashMap<Integer, DiscretePoint>(points2.length);
        name2DisPoint = new HashMap<String, DiscretePoint>(points2.length);
        for (DiscretePoint p : points2) {
            discreatePoints.put(p.getId(), p);
            name2DisPoint.put(p.getName(), p);
        }
    }

    public boolean containsYC(int rtuId, int pointNum) {
        int id = MeasurePoint.getNID(rtuId, pointNum);
        return analogPoints.containsKey(id);
    }

    public boolean containsYC(String name) {
        return name2AlgPoint.containsKey(name);
    }

    public boolean containsYC(int id) {
        return analogPoints.containsKey(id);
    }

    public boolean containsYX(int rtuId, int pointNum) {
        int id = MeasurePoint.getNID(rtuId, pointNum);
        return discreatePoints.containsKey(id);
    }

    public boolean containsYX(String name) {
        return name2DisPoint.containsKey(name);
    }

    public boolean containsYX(int id) {
        return discreatePoints.containsKey(id);
    }

    public static PointManager getInstance() {
        if (instance == null)
            instance = new PointManager();
        return instance;
    }

    public MeasPersistence getPersistence() {
        return persistence;
    }

    public void setPersistence(MeasPersistence persistence) {
        this.persistence = persistence;
    }

    public boolean addAnalogPoints(AnalogPoint[] points) {
        List<AnalogPoint> toSave = new ArrayList<AnalogPoint>(points.length);
        for (AnalogPoint p : points)
            if (!analogPoints.containsKey(p.getId()))
                toSave.add(p);
        if (persistence.addAnalogPoints(toSave.toArray(new AnalogPoint[]{}))) {
            for (AnalogPoint p : toSave) {
                analogPoints.put(p.getId(), p);
                name2AlgPoint.put(p.getName(), p);
            }
            return true;
        }
        return false;
    }

    public boolean removeDiscretePoint(int pointId) {
        boolean r = persistence.removeDiscretePoint(pointId);
        if (r) {
            DiscretePoint p = discreatePoints.remove(pointId);
            if (p != null)
                name2DisPoint.remove(p.getName());
        }
        return r;
    }

    public boolean removeDiscretePoint(DiscretePoint point) {
        return removeDiscretePoint(point.getId());
    }

    public boolean removeAnalogPoint(int pointId) {
        boolean r = persistence.removeAnalogPoint(pointId);
        if (r) {
            AnalogPoint p = analogPoints.remove(pointId);
            if (p != null)
                name2AlgPoint.remove(p.getName());
        }
        return r;
    }

    public boolean removeAnalogPoint(AnalogPoint point) {
        return removeAnalogPoint(point.getId());
    }

    public boolean addDiscretePoints(DiscretePoint[] points) {
        List<DiscretePoint> toSave = new ArrayList<DiscretePoint>(points.length);
        for (DiscretePoint p : points)
            if (!discreatePoints.containsKey(p.getId()))
                toSave.add(p);
        if (persistence.addDiscretePoints(toSave.toArray(new DiscretePoint[]{}))) {
            for (DiscretePoint p : toSave) {
                discreatePoints.put(p.getId(), p);
                name2DisPoint.put(p.getName(), p);
            }
            return true;
        }
        return false;
    }

    public AnalogPoint getAnalogPoint(String name) {
        return name2AlgPoint.get(name);
    }

    public AnalogPoint getAnalogPoint(int pointId) {
        return analogPoints.get(pointId);
    }

    public AnalogPoint getAnalogPoint(int rtuId, int pointNum) {
        return analogPoints.get(MeasurePoint.getNID(rtuId, pointNum));
    }

    public DiscretePoint getDiscretePoint(String name) {
        return name2DisPoint.get(name);

    }

    public DiscretePoint getDiscretePoint(int pointId) {
        return discreatePoints.get(pointId);
    }

    public DiscretePoint getDiscretePoint(int rtuId, int pointNum) {
        return discreatePoints.get(MeasurePoint.getNID(rtuId, pointNum));
    }

    public AnalogPoint[] getAnalogPoints(int rtuId) {//todo: not efficient
        List<AnalogPoint> points = new ArrayList<AnalogPoint>();
        for (AnalogPoint p : analogPoints.values())
            if (p.getRtuId() == rtuId)
                points.add(p);
        return points.toArray(new AnalogPoint[]{});
    }

    public DiscretePoint[] getDiscretePoints(int rtuId) {//todo: not efficient
        List<DiscretePoint> points = new ArrayList<DiscretePoint>();
        for (DiscretePoint p : discreatePoints.values())
            if (p.getRtuId() == rtuId)
                points.add(p);
        return points.toArray(new DiscretePoint[]{});
    }

    public boolean addMeasurePoint(MeasurePoint point) {
        if (persistence.addMeasurePoint(point)) {
            if (point instanceof AnalogPoint) {
                analogPoints.put(point.getId(), (AnalogPoint) point);
                name2AlgPoint.put(point.getName(), (AnalogPoint) point);
            } else {
                discreatePoints.put(point.getId(), (DiscretePoint) point);
                name2DisPoint.put(point.getName(), (DiscretePoint) point);
            }
            return true;
        }
        return false;
    }

    public boolean updateMeasurePoint(MeasurePoint point) {
        if (persistence.updateMeasurePoint(point)) {
            if (point instanceof AnalogPoint) {
                analogPoints.put(point.getId(), (AnalogPoint) point);
                name2AlgPoint.put(point.getName(), (AnalogPoint) point);
            } else {
                discreatePoints.put(point.getId(), (DiscretePoint) point);
                name2DisPoint.put(point.getName(), (DiscretePoint) point);
            }
            return true;
        }
        return false;
    }

    public boolean updateAnalogs(AnalogPoint[] points) {
        if (persistence.updateAnalogPoints(points)) {
            for(AnalogPoint point : points){
                analogPoints.put(point.getId(), point);
                name2AlgPoint.put(point.getName(), point);
            }
            return true;
        }
        return false;
    }

    public boolean updateDiscretes(DiscretePoint[] points) {
        if (persistence.updateDiscretePoints(points)) {
            for(DiscretePoint point : points){
                discreatePoints.put(point.getId(), point);
                name2DisPoint.put(point.getName(), point);
            }
            return true;
        }
        return false;
    }

    public Map<Integer, AnalogPoint> getAnalogPoints() {
        return analogPoints;
    }

    public Map<Integer, DiscretePoint> getDiscreatePoints() {
        return discreatePoints;
    }

    public List<CommUnit> getCommUnits() {
        return commUnits;
    }

    public void remove() {
        for(CommUnit unit : commUnits)
            persistence.removeRtu(unit.getId());
    }

    public void updateRtuName(String name) {
        if (commUnits.size() == 1)
            persistence.updateRtu(commUnits.get(0).getId(), name);
    }
}
